class LightTip extends HTMLElement {
  // 定义需要观察的属性
  static get observedAttributes() {
    return ["open"];
  }

  constructor() {
    super();

    // 如果有参数传入，则调用自定义方法
    if (arguments.length) {
      LightTip.custom.apply(this, arguments);
    }
  }

  // 获取type属性
  get type() {
    return this.getAttribute("type");
  }

  // 获取time属性，如果time属性不是数字，则默认为3000
  get time() {
    let strTime = this.getAttribute("time");
    if (!isNaN(strTime) && !isNaN(parseFloat(strTime))) {
      return Number(strTime);
    }

    return 3000;
  }

  // 设置type属性
  set type(value) {
    this.setAttribute("type", value);
  }

  // 设置time属性
  set time(value) {
    this.setAttribute("time", value);
  }

  // 获取open属性，判断是否有open属性
  get open() {
    return this.hasAttribute("open");
  }

  // 设置open属性，如果value为true，则添加open属性，否则移除open属性
  set open(value) {
    this.toggleAttribute("open", value);
  }

  // 当自定义元素被插入到DOM中时调用
  connectedCallback() {
    // 自定义元素设置 tabIndex=0 代表改元素可聚焦，并可通过键盘导航来聚焦到该元素
    this.setAttribute("tabIndex", 0);
    this.setAttribute("role", "tooltip");

    // 如果没有closeMode属性，则默认为hide
    if (!this.closeMode) {
      this.closeMode = "hide";
    }

    // 点击组件本身或按键盘 esc/enter 键即可关闭组件
    this.addEventListener("click", () => {
      // 移除元素
      this[this.closeMode]();
    });

    // 全局事件
    this.dispatchEvent(
      new CustomEvent("connected", {
        detail: {
          type: "ui-lighttip",
        },
      })
    );

    this.isConnectedCallback = true;
  }

  // 当自定义元素的属性发生变化时调用
  attributeChangedCallback(name, oldValue, newValue) {
    // 让按钮或者之前的触发元素重新获取焦点，便于继续操作
    if (name == "open" && typeof oldValue !== typeof newValue) {
      if (typeof newValue === "string") {
        clearTimeout(this.timer);
        this.timer = setTimeout(() => {
          // 标志量，是否是因为时间到关闭
          this.isTimeHide = true;
          // 关闭提示
          this[this.closeMode]();
          this.position();
        }, this.time);

        this.setAttribute("data-tid", this.timer);
        this.classList.add("ESC");

        // 组件的 z-index 层级计算
        this.zIndex();

        // 组件的定位，不同的提示位置不重叠
        this.position();
      } else {
        this.classList.remove("ESC");
      }
      this.tabIndex();

      this.isTimeHide = null;
    }
  }

  // 组件的 z-index 层级计算
  zIndex() {
    // 只对<body>子元素进行层级最大化计算处理，这里lighttip默认的z-index值是19
    var numZIndexNew = 19;
    this.parentElement &&
      [...this.parentElement.childNodes].forEach(function (eleChild) {
        if (eleChild.nodeType != 1) {
          return;
        }
        var objStyleChild = window.getComputedStyle(eleChild);
        var numZIndexChild = objStyleChild.zIndex * 1;
        if (numZIndexChild && objStyleChild.display != "none") {
          numZIndexNew = Math.max(numZIndexChild + 1, numZIndexNew);
        }
      });
    this.style.zIndex = numZIndexNew;
  }

  // 定位处理
  position() {
    var elesOpen = [
      ...document.querySelectorAll('ui-lighttip[open]:not([type="loading"])'),
    ];
    // 基于 data-tid 排序
    var elesOpenSort = elesOpen.sort(function (eleA, eleB) {
      return (
        (eleA.getAttribute("data-tid") || 0) -
        (eleB.getAttribute("data-tid") || 0)
      );
    });
    // 确定提示内容
    var objMatchText = {};
    var numIndex = -1;

    elesOpenSort.forEach((ele) => {
      let strText = ele.textContent;
      if (typeof objMatchText[strText] == "undefined") {
        numIndex++;
        objMatchText[strText] = numIndex;
      }
      ele.style.setProperty("--ui-sort-index", objMatchText[strText]);
    });
  }

  // 新的元素层级总是最高
  tabIndex() {
    var eleContainer = this;
    var eleLastActive = LightTip.lastActiveElement;
    if (this.open == true) {
      var eleActiveElement = document.activeElement;

      // 键盘索引起始位置定位在提示元素上
      if (eleActiveElement && !eleActiveElement.closest("[keepfocus]")) {
        if (eleContainer !== eleActiveElement) {
          LightTip.lastActiveElement = eleActiveElement;
        }

        eleContainer.focus();
      }
    } else if (eleLastActive && !eleLastActive.matches("body")) {
      // 获取焦点但不会定位
      eleLastActive.focus({
        preventScroll: true,
      });
      // 如果不是键盘关闭提示，而是点击的话，之前的焦点元素失焦
      // 这里实现有问题，如果是时间到了自动关闭的话，这里不应该失焦
      if (!window.isKeyEvent && !this.isTimeHide) {
        eleLastActive.blur();
      }
      LightTip.lastActiveElement = null;
    }
    return this;
  }

  // success
  static success(text, time = 3000) {
    return this.custom(text, "success", time);
  }
  // error
  static error(text, time = 3000) {
    return this.custom(text, "error", time);
  }
  // normal
  static normal(text, time = 3000) {
    return this.custom(text, "normal", time);
  }
  // loading
  static loading(text) {
    text = text || "正在加载中...";
    return this.custom(text, "loading");
  }
  // 调用方法处理
  static custom(text = "", type, time) {
    // 如果是静态方法执行
    // 创建ui-lighttip自定义元素
    if (!this.matches || !this.matches("ui-lighttip")) {
      return LightTip.custom.apply(
        document.createElement("ui-lighttip"),
        arguments
      );
    }

    if (typeof text == "object") {
      type = text;
      text = "";
    }

    if (typeof text != "string") {
      return this;
    }

    this.closeMode = "remove";

    // 如果传入的类型是object形式
    if (type && typeof type === "object") {
      LightTip.custom.call(this, text, type.type, type.time);
      return;
    }
    // 如果type的类型是number，则赋值给time
    if (typeof type === "number") {
      LightTip.custom.call(this, text, time, type);
      return;
    }

    if (type == "loading") {
      if (!text) {
        text = "正在加载中...";
      }
      time = 999999;
    }

    if (time) {
      this.time = time;
    }
    if (type) {
      this.type = type;
    }

    this.innerHTML = text;
    // 提高无障碍
    if (type == "success") {
      this.setAttribute("aria-lable", "操作成功");
    } else if (type == "error") {
      this.setAttribute("aria-lable", "操作失败");
    }

    // append内存中创建的ui-lighttip元素
    if (!this.parentElement) {
      document.body.appendChild(this);

      this.dispatchEvent(new CustomEvent("DOMContentLoaded"));
    }

    this.show();

    return this;
  }

  // 移除元素
  remove() {
    if (this.parentElement) {
      this.parentElement.removeChild(this);
    }
    this.open = false;
  }

  // 显示元素
  show() {
    if (this.time > 0) {
      this.open = true;
    }
  }

  // 隐藏元素
  hide() {
    this.open = false;
  }
}

if (!customElements.get("ui-lighttip")) {
  customElements.define("ui-lighttip", LightTip);
}

// 将该方法定义为 window 全局使用的方法
window.LightTip = LightTip;

export default LightTip;
